using System;
using System.Collections.Generic;
using System.Linq;
using Krypton;
using Krypton.Lights;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace KryptonTest {

    public class Game1 : Game {

        private GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;
        private KryptonEngine krypton;
        private Texture2D mLightTexture;
        private Texture2D tile;

        public Game1() {
            graphics = new GraphicsDeviceManager(this) {PreferredBackBufferWidth = 1280, PreferredBackBufferHeight = 720};
            // Allow the window to be resized (to demonstrate render target recreation)
            Window.AllowUserResizing = true;
            Content.RootDirectory = "Content";
            // Create Krypton
            krypton = new KryptonEngine(this, "KryptonEffect") {SpriteBatchCompatablityEnabled = true, CullMode = CullMode.None};
        }

        protected override void Initialize() {
            krypton.Initialize();
            base.Initialize();
        }

        protected override void LoadContent() {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            // Create a new simple point light texture to use for the lights
            mLightTexture = LightTextureBuilder.CreatePointLight(GraphicsDevice, 512);
            tile = Content.Load<Texture2D>("tile");
            // Create some lights and hulls
            CreateLights(mLightTexture);
            CreateHulls();
        }

        private void CreateLights(Texture2D texture) {
            Light2D light = new Light2D {
                Texture = texture,
                Range = 50, // In the grid created by the orthogonic projection units. This is the radius of the light's circle.
                Color = Color.WhiteSmoke,
                Intensity = 1f, // 0 to 3.
                Angle = MathHelper.TwoPi*.25f, // 0 to 1. Rotates clockwise. 0 and 1 face right.
                X = 100f, // In the grid created by the orthogonic projection units. 0 is the center of the screen. 
                Y = 100f,
                Fov = MathHelper.TwoPi*.25f, // 0 to 1. 0.1 is very thin, 1 is a full circle.
            };
            krypton.Lights.Add(light);
        }

        private void CreateHulls() {
            var shadowHull = ShadowHull.CreateRectangle(new Vector2(4)); // Size.
            shadowHull.Position = new Vector2(-2); // The center of the hull.
            krypton.Hulls.Add(shadowHull);
        }

        protected override void Update(GameTime gameTime) {
            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime) {
            // Assign the matrix and pre-render the lightmap.
            // Make sure not to change the position of any lights or shadow hulls after this call, as it won't take effect till the next frame!
            krypton.Matrix = Matrix.Identity;//*view*projection; // TODO: this would be the camera's matrix...
            krypton.Bluriness = 3;
            krypton.LightMapPrepare();

            // Make sure to clear the backbuffer *after* Krypton is done pre-rendering.
            GraphicsDevice.Clear(Color.White);

            // ----- DRAW STUFF HERE ----- //
            // By drawing here, you ensure that your scene is properly lit by krypton.
            // Drawing after KryptonEngine.Draw will cause you objects to be drawn on top of the lightmap (can be useful, fyi)
            spriteBatch.Begin();
            for (int i = 0; i < 1280; i += tile.Bounds.Width) {
                for (int j = 0; j < 720; j += tile.Bounds.Height) {
                    spriteBatch.Draw(tile, new Vector2(i, j), Color.White);
                }
            }
            spriteBatch.End();
            // ----- DRAW STUFF HERE ----- //

            // Draw krypton (This can be omited if krypton is in the Component list. It will simply draw krypton when base.Draw is called
            krypton.Draw(gameTime);

            // Draw the shadow hulls as-is (no shadow stretching) in pure white on top of the shadows
            // You can omit this line if you want to see what the light-map looks like :)
            DebugDraw();

            base.Draw(gameTime);
        }

        private void DebugDraw() {
            krypton.RenderHelper.Effect.CurrentTechnique = krypton.RenderHelper.Effect.Techniques["DebugDraw"];
            GraphicsDevice.RasterizerState = new RasterizerState {
                CullMode = CullMode.None,
                FillMode = FillMode.WireFrame,
            };
            if (Keyboard.GetState().IsKeyDown(Keys.H)) {
                // Clear the helpers vertices
                krypton.RenderHelper.ShadowHullVertices.Clear();
                krypton.RenderHelper.ShadowHullIndicies.Clear();
                foreach (var hull in krypton.Hulls) {
                    krypton.RenderHelper.BufferAddShadowHull(hull);
                }
                foreach (var effectPass in krypton.RenderHelper.Effect.CurrentTechnique.Passes) {
                    effectPass.Apply();
                    krypton.RenderHelper.BufferDraw();
                }
            }
            if (Keyboard.GetState().IsKeyDown(Keys.L)) {
                krypton.RenderHelper.ShadowHullVertices.Clear();
                krypton.RenderHelper.ShadowHullIndicies.Clear();
                foreach (Light2D light in krypton.Lights) {
                    krypton.RenderHelper.BufferAddBoundOutline(light.Bounds);
                }
                foreach (var effectPass in krypton.RenderHelper.Effect.CurrentTechnique.Passes) {
                    effectPass.Apply();
                    krypton.RenderHelper.BufferDraw();
                }
            }
        }

    }

}